<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    const PENDING = 'pending';
    const FULLFILLED = 'fulfilled';
    const REJECTED = 'rejected';

    function runAsynctask(callback) { // 这里原本是需要使用MutationObserver的
      // 但是MutationObserver使用起来比较的复杂，所以这里就是用了这个queueMicrotask和setTimeout来模拟异步
      if (typeof queueMicrotask === "function") {
        queueMicrotask(callback); // 放在微任务队列中
      } else {
        setTimeout(callback, 0); // 放在宏任务队列中
      }
    }

    function resolvePromise(p2, x, resolve, reject) {
      // 判断x和p2是否指向同一个对象
      if (x === p2) {
        throw new TypeError('Chaining cycle detected for promise #<Promise>')
      }
      // 判断x是否是一个promise对象
      if (x instanceof MyPromise) {
        // 如果是就执行了then方法，将结果传给这个外面的MyPromise对象
        x.then(res => resolve(res), err => reject(err));
      } else {
        resolve(x); // 调用resolve函数，将返回值传给下一个then
      }
    }

    class MyPromise {
      // 添加状态
      state = PENDING;
      // 添加原因，保存成功或者失败的原因
      reason = undefined;
      // 保存成功或者失败的回调函数，用于实现异步
      #handlers = [];
      // 构造函数
      constructor(func) {
        const resolve = (value) => {
          if (this.state === PENDING) {
            this.state = FULLFILLED;
            this.reason = value;
            // 执行成功的回调函数
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.reason);
            })
          }
        }

        const reject = (reason) => {
          if (this.state === PENDING) {
            this.state = REJECTED;
            this.reason = reason;
            // 执行失败的回调函数
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.reason);
            })
          }
        }

        try {
          func(resolve, reject);
        } catch (err) {
          reject(err);
        }
      }
      // then方法
      then(onFulfilled, onRejected) {
        // 处理成功的回调函数，如果没有传入，就赋值一个恒等的函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        // 处理失败的回调函数，如果没有传入，就抛出错误
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

        const p2 = new MyPromise((resolve, reject) => {
          // 在这里面的函数方法是立刻同步执行的
          // 但是放在外面也可以，之所以放在这里是因为这里可以获取到resolve和reject函数
          // 根据状态执行对应的回调函数
          if (this.state === FULLFILLED) {
            // 在执行成功的回调之前，就直接将回调函数放入微任务队列中
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.reason); // 保存成功的返回值
                /* // 判断x和p2是否指向同一个对象
                if (x === p2) {
                  throw new TypeError('Chaining cycle detected for promise #<Promise>')
                }
                // 判断x是否是一个promise对象
                if (x instanceof MyPromise) {
                  // 如果是就执行了then方法，将结果传给这个外面的MyPromise对象
                  x.then(res => resolve(res), err => reject(err));
                } else {
                  resolve(x); // 调用resolve函数，将返回值传给下一个then
                } */
                resolvePromise(p2, x, resolve, reject);
              } catch (err) {
                reject(err); // 调用reject函数，将错误传给下一个then
              }
            })
          } else if (this.state === REJECTED) {
            // 在执行失败的回调之前，就直接将回调函数放入微任务队列中
            runAsynctask(() => {
              try {
                const x = onRejected(this.reason); // 保存失败的原因

                resolvePromise(p2, x, resolve, reject);
              } catch (err) {
                reject(err); // 调用reject函数，将错误传给下一个then
              }
            })
          } else if (this.state === PENDING) { // 代码能走到这里说明这里这里就需要异步执行
            this.#handlers.push({ // 将需要异步执行的函数变成对象放入数组中
              onFulfilled: () => { // 在这里如果是直接使用了runAsynctask(() => { onFulfilled(this.reason); })会直接执行而不是异步在调用的时候执行
                // 在这里是直接使用一个箭头函数，而不是一个runAsynctask(() => { onFulfilled(this.reason); })
                // 因为如果直接使用这个函数的话，会导致函数走到这里的时候直接执行而不是异步执行
                runAsynctask(() => {
                  try {
                    const x = onFulfilled(this.reason);
                    resolvePromise(p2, x, resolve, reject);
                  } catch (err) {
                    reject(err)
                  }
                })
              }, onRejected: () => {
                runAsynctask(() => {
                  try {
                    const x = onRejected(this.reason);
                    resolvePromise(p2, x, resolve, reject);
                  } catch (err) {
                    reject(err)
                  }
                })
              }
            })
          }
        })

        return p2;
      }
      // catch方法
      catch(onRejected) {
        return this.then(null, onRejected);
      }
      // finally方法
      finally(onFinally) {
        return this.then(onFinally, onFinally);
      }
      // resolve方法
      static resolve(value) {
        if (value instanceof MyPromise) {
          return value;
        }

        return new MyPromise((resolve) => {
          resolve(value);
        })
      }
      // reject方法
      static reject(reason) {
        return new MyPromise((undefined, reject) => {
          reject(reason);
        })
      }
      // race方法
      static race(promises) {
        return new MyPromise((resolve, reject) => {
          // 判断promises是否是一个数组
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Arguments must be an array'));
          }

          promises.forEach(promise => {
            // 这里调用resolve方法，是为了让每一个promise方法都可以使用.then方法
            MyPromise.resolve(promise).then(res => {
              resolve(res); // 敲定返回的MyPromise对象的状态
            }, err => {
              reject(err); // 敲定返回的MyPromise对象的状态
            })
          })
        });
      }
      // all方法
      static all(promises) {
        return new MyPromise((resolve, reject) => {
          // 判断promises是否是一个数组
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Arguments must be an array'));
          }
          // 空数组直接兑现
          promises.length === 0 && resolve(promises);

          let arr = [];
          let count = 0;

          promises.forEach((promise, index) => {
            MyPromise.resolve(promise).then(res => {
              arr[index] = res;
              count++;
              count === promises.length && resolve(arr);
            }, err => {
              reject(err);
            })
          })
        })
      }
      // allSettled方法
      static allSettled(promises) {
        return new MyPromise((resolve, reject) => {
          // 判断promises是否是一个数组
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Arguments must be an array'));
          }

          // 空数组直接兑现
          promises.length === 0 && resolve(promises);

          let arr = [];
          let count = 0;
          promises.forEach((promise, index) => {
            MyPromise.resolve(promise).then(res => {
              arr[index] = { status: FULLFILLED, value: res };
              count++;
              count === promises.length && resolve(arr);
            }, err => {
              arr[index] = { status: REJECTED, reason: err };
              count++;
              count === promises.length && resolve(arr);
            });
          })
        })
      }
      // any方法
      static any(promises) {
        return new MyPromise((resolve, reject) => {
          // 判断promises是否是一个数组
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Arguments must be an array'));
          }

          // 空数组直接兑现
          promises.length === 0 && reject(new AggregateError(promises, 'All promises were rejected'));

          let arr = [];
          let count = 0;
          promises.forEach((promise, index) => {
            MyPromise.resolve(promise).then(res => {
              // 只要有一个成功了就返回第一个成功的结果
              resolve(res);
            }, err => {
              arr[index] = err;
              count++;
              console.log(arr);
              count === promises.length && reject(new AggregateError(arr, 'All promises were rejected'));
            })
          })
        })
      }
    }

    // 测试代码，测试MyPromise的any方法
    function testMyPromise15() {
      const p1 = MyPromise.reject("p1");
      const p2 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          reject("p2");
        }, 2000);
      })
      const p4 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          reject("p4");
        }, 3000);
      })
      const p3 = MyPromise.reject("p3");

      MyPromise.any([p1, p2, p3, p4]).then(res => {
        console.log("成功返回了", res);
      }, err => {
        console.dir(err); // 这个AggregateError是对象，使用log是无法打印这个对象的
      })
    }
    // testMyPromise15();

    // 测试代码，测试MyPromise的allSettled方法
    function testMyPromise14() {
      const p1 = 1;
      const p2 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(2);
        }, 2000)
      })
      const p3 = MyPromise.reject("失败了");
      MyPromise.allSettled([p1, p2, p3]).then(res => {
        console.log("成功返回了", res);
      }, err => {
        console.log("返回失败了", err);
      })
    }
    // testMyPromise14();

    // 测试代码，测试MyPromise的all方法
    function testMyPromise13() {
      const p1 = MyPromise.resolve(1);
      const p2 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(2);
        }, 2000);
      })
      const p3 = 3;

      MyPromise.all([p1, p2, p3]).then(res => {
        console.log("成功返回了", res);
      }, err => {
        console.log("返回失败了", err);
      })
    }
    // testMyPromise13();

    // 测试代码，测试MyPromise的race方法
    function testMyPromise12() {
      const p1 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          reject("p1");
        }, 2000);
      })
      const p2 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          reject("p2");
        }, 1000);
      });

      MyPromise.race([p1, p2]).then(value => {
        console.log("成功了", value);
      }, err => {
        console.log("失败了", err);
      })
    }
    // testMyPromise12();

    // 测试代码，测试MyPromise的reject方法
    function testMyPromise11() {
      MyPromise.reject("失败了").catch(err => {
        console.log("捕获了", err);
        return new MyPromise((resolve, reject) => {
          reject("又失败了");
        })
      }).catch(err => { // 这里一个catch会对应一个Promise的失败，所以这里的catch不会捕获到第一个Promise的失败
        console.log("又捕获了", err);
      })
    }
    // testMyPromise11();

    // 测试代码，测试MyPromise的resolve方法
    function testMyPromise10() {
      const p = MyPromise.resolve(new MyPromise((resolve, reject) => {
        // resolve(1);
        reject(2);
      }))

      p.then(res => {
        console.log("成功了", res);
      }, err => {
        console.log("失败了", err);
      }).catch(err => {
        console.log("捕获了", err);
      }).finally(() => {
        console.log("结束了");
      })

      MyPromise.resolve("testText").then(res => {
        console.log("成功了在这个地方", res);
      })
    }
    // testMyPromise10();

    // 测试代码，测试MyPromise的finally方法
    function testMyPromise9() {
      const p = new MyPromise((resolve, reject) => {
        // resolve(1);
        throw "这里错误了"
      })

      p.then(res => {
        console.log("成功了", res);
      }, err => {
        console.log("失败了", err);
      }).catch(err => {
        console.log("捕获了", err);
      }).finally(() => {
        console.log("结束了");
      });
    }
    // testMyPromise9();

    // 测试代码，测试catch方法
    function testMyPromise8() {
      const p = new MyPromise((resolve, reject) => {
        // reject(1);
        throw "这里错误了"
      })

      p.then(res => {
        console.log("resolve-then", res);
      }, err => {
        console.log("reject-then", err);
      }).catch(err => {
        console.log("捕获了", err);
      })
    }
    // testMyPromise8();

    // 测试代码，测试MyPromise的then方法
    function testMyPromise1() {
      const p = new MyPromise((resolve, reject) => {
        resolve("成功了ssssssssss") // 这里是直接制定了state的状态了
        // 走到了resolve函数这里，改变了state的状态，执行了handlers中的函数
        // 但是这时的handlers中是空的，所以就没有任何效果，因为handlers中是空的
        // 当调用then方法的时候，发现state是resolved，就直接执行成功的回调函数
        // 用于放在了微任务中，所以会慢于同步任务，所以会在"开始执行"和"结束执行"之后输出"成功了"
      });

      console.log("开始执行");
      p.then(value => {
        console.log("成功了", value);
      })
      console.log("结束执行");
    }
    // testMyPromise1();

    // 测试代码，测试MyPromise的链式调用和错误处理
    function testMyPromise2() {
      const p = new MyPromise((resolve, reject) => {
        resolve("成功了")
      });

      p.then(value => {
        console.log("成功了ssss", value);
        throw "zzzzzzzzz"
        return 3
      }).then(value => {
        console.log("成功了dddddddd", value);
      }, err => {
        console.log("失败了wwww", err);
      })
    }
    // testMyPromise2();

    // 测试代码，测试MyPromise的链式调用和返回一个新的MyPromise对象
    function testMyPromise3() {
      const p = new MyPromise((resolve, reject) => {
        resolve("成功了1111111")
      });

      p.then(value => {
        return new MyPromise((resolve, reject) => {
          resolve("成功了ssss")
        });
      }).then(value => {
        console.log("成功了dddddddd", value);
      }, err => {
        console.log("失败了wwww", err);
      })
    }
    // testMyPromise3();

    // 测试代码，测试MyPromise的处理重复引用
    function testMyPromise4() {
      // 发现问题，这里没有向Promise一样直接抛出错误，而是当下一次调用时.then方法才会抛出错误
      // 在写到这里的时候，还没有进行错误处理，我估计是还没有做错误处理有关，所以这里的错误处理还不够完善
      const p = new MyPromise((resolve, reject) => {
        resolve("成功了2222222")
      });

      const p2 = p.then(value => {
        console.log("成功了ssss", value);
        return p2;
      })

      p2.then(value => {
        console.log("这里");
      })
    }
    // testMyPromise4();

    // 测试代码，测试Promise时发现问题
    function testMyPromise5() {
      const p = new Promise(resolve => {
        // 在Promise中抛出的错误是会被捕获然后变成reject状态的
        // 但是在这里是先resolve了，Promise的状态已经是resolved了，所以不会再执行失败的回调函数
        resolve("成功了3333333")
        throw "dddddddddddd"
      })

      p.then(value => {
        console.log("成功了ssss", value);
      }, err => {
        console.log("失败了wwww", err);
      })
    }
    // testMyPromise5();

    // 测试代码，测试MyPromise的状态
    function testMyPromise6() {
      const p = new MyPromise((resolve, reject) => {
        // resolve(1);
        reject(2) // 这里已经敲定了p的状态了
      });

      const p2 = p.then(undefined, err => {
        return 2; // 
      })

      p2.then(value => {
        console.log("p2-resolve", value);
      }, err => {
        console.log("p2-reject", err);
      })
    }
    // testMyPromise6();

    // 测试代码，测试MyPromise的PENDING状态
    function testMyPromise7() {
      const p = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(1);
        }, 2000);
      })

      const p2 = p.then(value => {
        // return 2;
        // return p2;
        return new MyPromise((resolve, reject) => {
          // resolve(2);
          reject(3);
        });
      });

      p2.then(value => {
        console.log("p2-resolve", value);
      }, err => {
        console.log("p2-reject", err);
      });
    }
    // testMyPromise7();
  </script>
</body>

</html>